﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ExpreRec.Logic.Model;
using System.Threading;
using ExpreRec.Logic.Expression;
using System.IO;
using ExpreRec.DataAccess;

namespace ExpreRec.UI
{
    public partial class KNNTrainingForm : Form
    {
        private delegate void refreshActionType(int k, double r, bool distVote, int result);
        private delegate void finishActionType(bool manualStop);

        private bool threadRunningFlag = false;

        private IList<string> expressionTypes;
        private IList<GaborItem> gaborItems;

        private Thread innerThread;
        private refreshActionType refreshAction;
        private finishActionType finishAction;

        private IList<int> kList = new List<int>();
        private IList<double> rList = new List<double>();
        private IList<bool> distFlagList = new List<bool>();

        private bool closingFlag = false;

        private int processed;
        private int total;

        private static Classification classifier = new Classification();

        private static VariableDAL dal = new VariableDAL();

        public KNNTrainingForm()
        {
            InitializeComponent();
            refreshAction = new refreshActionType(updateUI);
            finishAction = new finishActionType(finished);
        }

        private void TrainingPreprocessForm_Load(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Maximized;
        }

        private string[] split(string text)
        {
            string[] splits = text.Split(new char[] { ',', '，', ';' }, StringSplitOptions.RemoveEmptyEntries);

            IList<string> res = new List<string>();

            IDictionary<string, int> dit = new Dictionary<string, int>();

            foreach (string s in splits)
            {
                if (!dit.ContainsKey(s))
                {
                    res.Add(s);
                    dit[s] = 0;
                }
            }

            return res.ToArray<string>();
        }

        private void buttonStart_Click(object sender, EventArgs e)
        {
            KeyValuePair<IList<string>, IList<GaborItem>> res = classifier.GaborKNNLoadModel();

            expressionTypes = res.Key;

            gaborItems = res.Value;

            if (expressionTypes.Count != 0 && gaborItems.Count != 0)
            {
                kList.Clear();
                rList.Clear();
                distFlagList.Clear();

                string[] splits = split(textBoxArgKs.Text);

                foreach (string s in splits)
                {
                    int o = -1;

                    if (int.TryParse(s, out o))
                    {
                        if (o >= 1 && o <= 50)
                            kList.Add(o);
                    }
                }

                splits = split(textBoxArgRs.Text);

                foreach (string s in splits)
                {
                    double o = -1;

                    if (double.TryParse(s, out o))
                    {
                        if (o > 0 && o <= 10)
                            rList.Add(o);
                    }
                }

                if (checkBoxDistVoteFalse.Checked)
                    distFlagList.Add(false);

                if (checkBoxDistVoteTrue.Checked)
                    distFlagList.Add(true);

                if (kList.Count != 0 && rList.Count != 0 && distFlagList.Count != 0)
                {
                    buttonStart.Enabled = false;
                    buttonStop.Enabled = true;
                    buttonSave.Enabled = false;

                    listViewLibs.Groups.Clear();
                    listViewLibs.Items.Clear();
                    listViewStatistics.Items.Clear();

                    labelCurrentBestK.Text = "未知";
                    labelCurrentBestR.Text = "未知";
                    labelCurrentBestResult.Text = "未知";
                    labelCurrentBestDistVote.Text = "未知";

                    foreach (string label in expressionTypes)
                    {
                        listViewLibs.Groups.Add(label, label);
                    }

                    progressBarProcess.Value = 0;
                    processed = 0;
                    total = kList.Count * rList.Count * distFlagList.Count;

                    for (int i = 0; i < gaborItems.Count; i++)
                    {
                        GaborItem item = gaborItems[i];
                        ListViewItem listViewItem = new ListViewItem(item.Label + "\\" + Path.GetFileName(item.FileName), listViewLibs.Groups[item.Label]);
                        listViewLibs.Items.Add(listViewItem);
                    }

                    threadRunningFlag = true;

                    innerThread = new Thread(new ThreadStart(threadMain));
                    innerThread.Name = "InnerThread";
                    innerThread.Start();
                }
                else
                {
                    MessageBox.Show("请输入正确的枚举参数！");
                }
            }
            else
            {
                MessageBox.Show("图片库不存在，请重新进行预处理！");
            }
        }

        private void buttonStop_Click(object sender, EventArgs e)
        {
            buttonStop.Enabled = false;
            threadRunningFlag = false;
        }

        protected void updateUI(int k, double r, bool distVote, int result)
        {
            if (result == -1)
            {
                labelNextDistVote.Text = distVote ? "是" : "否";
                labelNextK.Text = k.ToString();
                labelNextR.Text = r.ToString();
                labelNextResult.Text = "未知";
            }
            else
            {
                double resultDouble = (double)result * 100.0 / gaborItems.Count;

                labelNextResult.Text = result.ToString();

                int best = -1;
                if (!labelCurrentBestResult.Text.Equals("未知"))
                    best = int.Parse(labelCurrentBestResult.Text);

                if (result > best)
                {
                    labelCurrentBestDistVote.Text = distVote ? "是" : "否";
                    labelCurrentBestK.Text = k.ToString();
                    labelCurrentBestR.Text = r.ToString();
                    labelCurrentBestResult.Text = result.ToString();
                }

                ListViewItem item = new ListViewItem(k.ToString());
                item.SubItems.Add(r.ToString());
                item.SubItems.Add(distVote ? "是" : "否");
                item.SubItems.Add(resultDouble.ToString() + "%");

                listViewStatistics.Items.Add(item);

                processed++;

                progressBarProcess.Value = processed * 100 / total;
            }
        }

        protected void finished(bool manualStop)
        {
            if (!closingFlag)
            {
                buttonStart.Enabled = true;
                buttonSave.Enabled = true;
                buttonStop.Enabled = false;


                if (manualStop)
                    MessageBox.Show("训练操作被终止，但您仍然可以保存当前最优参数！");
                else
                    MessageBox.Show("训练操作全部结束，请保存当前最优参数！");
            }
        }

        private void threadMain()
        {
            foreach (int k in kList)
                foreach (double r in rList)
                    foreach (bool distFlag in distFlagList)
                    {
                        if (!threadRunningFlag)
                        {
                            if (!closingFlag)
                                this.Invoke(finishAction, new object[] { true });
                            return;
                        }

                        if (threadRunningFlag)
                        {
                            this.Invoke(refreshAction, new object[] { k, r, distFlag, -1 });
                        }

                        int result = classifier.GaborKNNLeaveOneOutClassification(expressionTypes, gaborItems, distFlag, r, k);

                        if (threadRunningFlag)
                        {
                            this.Invoke(refreshAction, new object[] { k, r, distFlag, result });
                        }
                    }

            this.Invoke(finishAction, new object[] { false });
        }

        private void TrainingPreprocessForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            closingFlag = true;
            if (threadRunningFlag)
            {
                threadRunningFlag = false;

                Thread.Sleep(100);
            }
        }

        private void buttonSave_Click(object sender, EventArgs e)
        {
            if (!labelCurrentBestResult.Text.Equals("未知"))
            {
                int k = int.Parse(labelCurrentBestK.Text);
                double r = double.Parse(labelCurrentBestR.Text);

                dal.UpdateValue("KNNParamK", labelCurrentBestK.Text);
                dal.UpdateValue("KNNParamDistR", labelCurrentBestR.Text);
                dal.UpdateValue("KNNParamDistVoteFlag", labelCurrentBestDistVote.Text.Equals("是") ? "1" : "0");

                MessageBox.Show("保存成功！");
            }
        }
    }
}
